import logging.config
import yaml
import os
from flask import Flask, Blueprint

from app.utils.core import JSONEncoder
from app.api.router import router
from app.module.OSSFlask import OSSClientFlask
from app.module.MachineState import MachineState
from app.utils.core import db
from app.module.SCPFlask import SCPClientFlask
# oss_client = OSSClientFlask()
scp_client = SCPClientFlask()
machine_state = MachineState()


def create_app(config_name=None, config_path=None):
    app = Flask(__name__)
    app.config['JSON_AS_ASCII'] = False
    app.json_encoder = JSONEncoder;
    # 读取配置文件
    if not config_path:
        pwd = os.getcwd()
        config_path = os.path.join(pwd, 'config/config.yaml')
    if not config_name:
        config_name = 'PRODUCTION'
    conf = read_yaml(config_name, config_path)
    app.config.update(conf)
    if not os.path.exists(app.config['LOGGING_PATH']):
        # 日志文件目录
        os.mkdir(app.config['LOGGING_PATH'])

    # 日志设置
    with open(app.config['LOGGING_CONFIG_PATH'], 'r', encoding='utf-8') as f:
        dict_conf = yaml.safe_load(f.read())
    logging.config.dictConfig(dict_conf)  # 载入日志配置

    # 注册接口
    register_api(app=app, routers=router)

    # 读取msg配置
    with open(app.config['RESPONSE_MESSAGE'], 'r', encoding='utf-8') as f:
        msg = yaml.safe_load(f.read())
        app.config.update(msg)

    # 初始化oss_client
    # oss_client.init_app(app)
    scp_client.init_app(app)

    # 初始化mysql
    db.app = app
    db.init_app(app)

    # 初始化machine_state
    machine_state.app = app
    machine_state.db = db
    machine_state.init_app(app, db)
    return app


def read_yaml(config_name, config_path):
    '''
    :param config_name: 读取配置文件路径
    :param config_path: 读取配置文件内容
    :return:
    '''
    if config_name and config_path:
        with open(config_path, 'r', encoding='UTF-8') as f:
            conf = yaml.safe_load(f.read())  # yaml.load(f.read())
        if config_name in conf.keys():
            return conf[config_name.upper()]
        else:
            raise KeyError('未找到对应的配置信息')
    else:
        raise ValueError('请输入正确的配置名称或配置文件路径')


def register_api(app, routers):
    for router_api in routers:
        if isinstance(router_api, Blueprint):
            app.register_blueprint(router_api)
        else:
            try:
                endpoint = router_api.__name__
                view_func = router_api.as_view(endpoint)
                # url默认为类名小写
                url = '/{}/'.format(router_api.__name__.lower())
                if 'GET' in router_api.__methods__:
                    app.add_url_rule(url, defaults={'key': None}, view_func=view_func, methods=['GET', ])
                    app.add_url_rule('{}<string:key>'.format(url), view_func=view_func, methods=['GET', ])
                if 'POST' in router_api.__methods__:
                    app.add_url_rule(url, view_func=view_func, methods=['POST', ])
                if 'PUT' in router_api.__methods__:
                    app.add_url_rule('{}<string:key>'.format(url), view_func=view_func, methods=['PUT', ])
                if 'DELETE' in router_api.__methods__:
                    app.add_url_rule('{}<string:key>'.format(url), view_func=view_func, methods=['DELETE', ])
            except Exception as e:
                raise ValueError(e)
